from ..bot_plugin import Bot_plugin
from ..nick_plugin.nick_plugin import Plugin_nick
from cqhttp import CQHttp
from bot_body import Bot_body
from tools.CQ_tools import group_msg_level
from tools.CQ_tools import query_group_info
from tools.CQ_tools import CQ_code_dealing

import pymysql
import logging
import colorful
# logging.basicConfig(level=logging.DEBUG)

class Bridge_manager():
    def __init__(self,
        dbfile = r'./data/qqspeed.db',
        tbl = 'bridges'
    ):
        self.dbfile = dbfile
        self.tbl = tbl
        self.cache = dict()
        self.init_db_test()

    def init_db_test(self):
        sql = "select * from {}".format(self.tbl)
        ret = self.execute(sql)
        if ret == None:
            raise Exception("dbfile[{}] has no table named {}".format(self.dbfile, self.tbl))
    
    def execute(self, sql:str):
        import sqlite3
        with sqlite3.connect(self.dbfile) as db:
            c = db.cursor()
            try:
                c.execute(sql)
                ans = c.fetchall()
                db.commit()
                return ans
            except:
                import traceback
                logging.warning(colorful.red("sql execute failed, sql={}\n Error msg={}".format(
                    sql, traceback.format_exc()
                )))
                db.rollback()
                return None
    def python_value_to_sql_value(self, value):
        if type(value) == str:
            return '"{}"'.format(value)
        else:
            return value
    def query(self, base_column:str, base_value, get_column:str):
        cache = self.cache
        if base_column not in cache:
            cache[base_column] = dict()
        cache = cache[base_column]
        if get_column not in cache:
            cache[get_column] = dict()
        cache = cache[get_column]
        if base_value in cache:
            return cache[base_value]

        base_value_in_sql = self.python_value_to_sql_value(base_value)
        sql = "select {get_column} from {tbl} where {base_column} = {base_value_in_sql}".format(
            get_column = get_column, tbl = self.tbl, base_column = base_column,
            base_value_in_sql = base_value_in_sql
        )
        data = self.execute(sql)
        if data == None:
            raise Exception("sql execution failed")
        if len(data)==0:
            cache[base_value] = []
        else:
            cache[base_value] = [v[0] for v in data]
        return cache[base_value]
    
    def update(self, base_column:str, base_value, get_column:str, get_value):
        old_values = self.query(base_column, base_value, get_column)
        if base_value in old_values: # already exists
            return True
        else: #insert
            get_value_in_sql = self.python_value_to_sql_value(get_value)
            base_value_in_sql = self.python_value_to_sql_value(base_value)
            sql = "insert into {tbl} ({base_column}, {get_column}) values ({base_value_in_sql}, {get_value_in_sql})".format(
                tbl=self.tbl, base_column=base_column, get_column=get_column,
                base_value_in_sql=base_value_in_sql, get_value_in_sql=get_value_in_sql
            )
            if self.execute(sql) != None:
                self.cache[base_column][get_column][base_value].append(get_value)
                try:
                    self.cache[get_column][base_column][get_value].append(base_column)
                except:
                    pass
                return True
            else:
                return False
    def delete(self, base_column:str, base_value, get_column:str, get_value):
        logging.debug(colorful.yellow("delete start"))
        old_values = self.query(base_column, base_value, get_column)
        get_value_in_sql = self.python_value_to_sql_value(get_value)
        base_value_in_sql = self.python_value_to_sql_value(base_value)
        logging.debug(colorful.yellow("delete:\told_values={}\tget_value={}\tget_value in old_values={}".format(old_values,get_value,get_value in old_values)))
        if get_value in old_values: # need to delete
            sql = "delete from {tbl} where {base_column} = {base_value_in_sql} and {get_column} = {get_value_in_sql}".format(
                tbl=self.tbl, base_column=base_column, get_column=get_column,
                base_value_in_sql=base_value_in_sql, get_value_in_sql=get_value_in_sql
            )
            logging.debug(colorful.yellow("delete: sql={}".format(sql)))
            if self.execute(sql) != None:
                self.cache[base_column][get_column][base_value].remove(get_value)
                try:
                    self.cache[get_column][base_column][get_value].remove(base_value)
                except:
                    pass
                return True
            else:
                return False
        else: # no need to delete
            # logging.debug(colorful.yellow("base_value={}\told_values={}".format(base_value, old_values)))
            return True
    def flash_all(self):
        self.cache.clear()

class Plugin_bridge_manager(Bot_plugin):
    def __init__(self, bot_body: Bot_body, name="manage bridge"):
        Bot_plugin.__init__(self, bot_body, name=name)
        self.bridge_manager = Bridge_manager()
        self.help_msg=r"""【群桥管理助手帮助】
0. 群桥帮助：显示本条信息【仅主人】
1. 群桥群号：显示本群群号【仅主人】
2. 群桥查询：显示所有群桥【仅主人】
3. 群桥添加123 456：添加群桥123->456【仅主人】
4. 群桥删除123 456：删除群桥123->456【仅主人】
"""
    def query_from(self, group_id:int)->list:
        '''
        返回数据库中转发向group_id的群列表，返回类型为[]
        '''
        return self.bridge_manager.query("group_id_to", group_id, "group_id_from")
    def query_to(self, group_id:int)->list:
        '''
        返回数据库中从group_id转发的群列表，返回类型为[]
        '''
        return self.bridge_manager.query("group_id_from", group_id, "group_id_to")
    def add_bridge(self, group_id_from:int, group_id_to:int):
        '''
        添加group_id_from --> group_id_to的群桥
        '''
        return self.bridge_manager.update('group_id_from', group_id_from, 'group_id_to', group_id_to)
    def delete_bridge(self, group_id_from:int, group_id_to:int):
        '''
        删除group_id_from --> group_id_to的群桥
        '''
        return self.bridge_manager.delete('group_id_from', group_id_from, 'group_id_to', group_id_to)
    
    def handle_msg(self, context):
        bot = self.bot
        raw_message = context['raw_message']
        msg_level = group_msg_level.judge(context, master_qqs=self.master_qqs)
        if raw_message == '群桥帮助' and msg_level >= group_msg_level.MASTER:
            bot.send(context, self.help_msg)
            return
        if raw_message== '群桥群号' and msg_level >= group_msg_level.MASTER:
            bot.send(context, "【群桥助手】本群群号为："+str(context['group_id']))
            return
        if raw_message == '群桥查询' and msg_level >= group_msg_level.MASTER:
            group_from = self.query_from(context['group_id'])
            group_to = self.query_to(context['group_id'])
            reply_msg = "本群群桥列表："
            for group in group_from:
                reply_msg = "{}\n{}({}) --> 本群".format(reply_msg, query_group_info.query_name(bot, group), group)
            for group in group_to:
                reply_msg = "{}\n本群 --> {}({})".format(reply_msg, query_group_info.query_name(bot, group), group)
            bot.send(context, reply_msg)
            return
        if raw_message[:4] == '群桥添加' and msg_level >= group_msg_level.MASTER:
            import re
            pattern = r'群桥添加(?P<group_id_from>\d{5,11}) (?P<group_id_to>\d{5,11})'
            ret = re.match(pattern, raw_message)
            if re == None:
                bot.send(context, self.help_msg)
            else:
                res = ret.groupdict()
                ret = self.add_bridge(res['group_id_from'],res['group_id_to'])
                reply_msg = "群桥添加成功：{group_name_from}({group_id_from} --> {group_name_to}({group_id_to})".format(
                    group_name_from = query_group_info.query_name(bot, res['group_id_from']),
                    group_id_from = res['group_id_from'],
                    group_name_to = query_group_info.query_name(bot,res['group_id_to']),
                    group_id_to = res['group_id_to']
                )
                bot.send(context, reply_msg)
        if raw_message[:4] == '群桥删除' and msg_level >= group_msg_level.MASTER:
            import re
            pattern = r'群桥删除(?P<group_id_from>\d{5,11}) (?P<group_id_to>\d{5,11})'
            ret = re.match(pattern, raw_message)
            if re == None:
                bot.send(context, self.help_msg)
            else:
                res = ret.groupdict()
                ret = self.delete_bridge(int(res['group_id_from']),int(res['group_id_to']))
                reply_msg = "群桥删除成功：{group_name_from}({group_id_from} --> {group_name_to}({group_id_to})".format(
                    group_name_from = query_group_info.query_name(bot, res['group_id_from']),
                    group_id_from = res['group_id_from'],
                    group_name_to = query_group_info.query_name(bot,res['group_id_to']),
                    group_id_to = res['group_id_to']
                )
                bot.send(context, reply_msg)



from collections import defaultdict
import time
import threading

class Plugin_bridge(Bot_plugin):
    def __init__(self, bot_body:Bot_body, bridge_manager:Plugin_bridge_manager, nick_manager:Plugin_nick, name="群转发助手"):
        Bot_plugin.__init__(self, bot_body, name=name)
        self.bridge_manager = bridge_manager
        self.nick_manager = nick_manager
        ret = self.bot.can_send_image()
        self.is_pro = ret['yes']
        self.cq_code_dealing = CQ_code_dealing(self.is_pro)
        self.max_interval = 60 # 最多60秒就转发一次
        self.max_msg_cnt = 10 # 最多10条消息就转发一次
        self.group_msg_cache = defaultdict(list)
        self.first_msg_time = dict()
        self.help_msg = r"""【群转发助手帮助】
0. 群转发帮助：显示本条信息【仅主人】
1. 群转发设置消息分割线****：每两条消息之间用****分割
2. 群转发设置最大缓存消息数10：最多10条消息就转发一次
3. 群转发设置最大缓存时间60：最多60秒就清空一次缓存
4. 群转发设置群来源开启：开启消息的来源群显示
5. 群转发设置群来源关闭：关闭消息的来源群显示
"""

    def to_clear_cache_every_max_interval(self, group_id:int, first_msg_time:int):
        time.sleep(self.max_interval)
        if self.first_msg_time[group_id] == first_msg_time:
            self.clear_group_msg_cache(group_id)

    def add_msg_to_group_cache(self, group_id:int, msg:str):
        '''
        添加msg到group_id对应的消息缓存中
        '''
        if not self.group_msg_cache[group_id]: #not null
            t = int(time.time())
            self.first_msg_time[group_id] = t
            thread = threading.Thread(target=self.to_clear_cache_every_max_interval, args=(group_id, t))
            thread.setDaemon(True)
            thread.start()
        self.group_msg_cache[group_id].append(msg)
        if len(self.group_msg_cache[group_id]) > self.max_msg_cnt:
            self.clear_group_msg_cache(group_id)
    
    def clear_group_msg_cache(self, group_id:int):
        if self.group_msg_cache[group_id] == []:
            return
        self.first_msg_time[group_id] = 0
        msg = '\n'.join(self.group_msg_cache[group_id])
        self.group_msg_cache[group_id] = []
        group_to = self.bridge_manager.query_to(group_id)
        for group in group_to:
            self.bot.send_group_msg(group_id=group, message=msg)
        time.sleep(1)

    def handle_msg(self, context):
        bot = self.bot
        raw_message = context['raw_message']
        msg_level = group_msg_level.judge(context, master_qqs=self.master_qqs)
        if msg_level >= group_msg_level.ANONYMOUS:
            group_id = context['group_id']
            group_to = self.bridge_manager.query_to(group_id)
            if group_to != []:
                msg_to_format, CQ_codes, CQ_codes_parsers = self.cq_code_dealing.resolve_CQ_code(raw_message)
                readable_CQ_codes = [self.cq_code_dealing.CQ_code_to_readable(
                    CQ_code_parser=v, query_nick=self.nick_manager.query_nick)
                    for v in CQ_codes_parsers]
                converted_msg = msg_to_format.format(*readable_CQ_codes)
                converted_msg = "{}:{}".format(self.nick_manager.query_nick(context['user_id']),converted_msg) if context['anonymous'] == None \
                    else "【匿名（{}）】:{}".format(context['anonymous']['name'], converted_msg)
                self.add_msg_to_group_cache(group_id, converted_msg)
                for i,v in enumerate(CQ_codes_parsers):
                    if self.cq_code_dealing.CQ_code_is_show_seperately(v['func']):
                        self.clear_group_msg_cache(group_id)
                        for group in group_to:
                            bot.send_group_msg(group_id=group, message=CQ_codes[i])


            
        
        


            





    
if __name__ == '__main__':
    pass
